【チュートリアル】ゼロから k3s クラスタを構築する

ヒント:本チュートリアルは Linux + fish shell に基づいて作成されており、一部のコマンド構文は Bash と若干異なります。自分のシステム環境に合わせてコマンドを調整してください。
はじめに
ご存知の通り、k3s は Rancher Labs によって開発された軽量な Kubernetes ディストリビューションであり、現在最も人気のある K8s 軽量化ソリューションです。
従来の運用方法(1Panel/宝塔/SSH など)と比較して、k3s の学習曲線はより急峻であり、より多くのコンテナオーケストレーション概念を理解する必要があります。しかし一度習得すれば、以下を得ることができます:
k3s のコア利点
- 軽量で効率的 - 単一のバイナリファイル、メモリ使用量 < 512MB、低スペック VPS に最適
- 本番環境対応 - Kubernetes API と完全互換、標準 K8s への円滑な移行が可能
- 宣言型運用 - YAML で期待状態を記述、システムが自動的に維持
- 高可用性保証 - 自動フェイルオーバー + マルチノード負荷分散
- すぐに使える - ネットワーク、ストレージ、Ingress などのコアコンポーネントが組み込み
k3s を通じて、複数の低価格 VPS を企業級の高可用クラスタに統合し、従来の運用では達成困難な自動化レベルを実現できます。
対象読者と準備
適切な対象者
- Linux の基礎知識がある開発者
- 従来の運用からコンテナオーケストレーションへの移行を希望する人
- 個人用の高可用サービスを構築したい技術愛好家
前提知識
- Linux コマンドラインの操作に精通していること
- Docker コンテナの基礎を理解していること
- 基本的なネットワーク知識(SSH、ファイアウォール)を持つこと
学習成果
本チュートリアルを完了すると、以下を習得できます:
- k3sup を使用した k3s クラスタの迅速なデプロイ
- k3s のコアコンポーネント(API Server、etcd、kubelet など)の役割の理解
- デフォルトコンポーネントの置き換えによるパフォーマンス最適化(Cilium CNI、Nginx Ingress など)
- 最初のアプリケーションのデプロイと外部アクセスの設定
- 基本的なクラスタ運用とトラブルシューティングのスキル
デプロイメント計画
k3s はデフォルトで簡潔なコンポーネントセットをインストールしますが、本番環境レベルの要件を満たすために、どのモジュールを保持または置き換えるかを事前に計画する必要があります。以下の表は推奨される取捨選択戦略を示しています:
| コンポーネントタイプ | k3s デフォルトコンポーネント | 置き換えコンポーネント | 置き換え理由 | k3sup 無効化パラメータ |
|---|---|---|---|---|
| コンテナランタイム | containerd | - | デフォルトのままで問題なし | - |
| データストレージ | SQLite / etcd | - | シングルノードは SQLite、クラスタは etcd | - |
| Ingress Controller | Traefik | Nginx Ingress / その他 | チームがより精通、機能要件が異なる | --disable traefik |
| LoadBalancer | Service LB (Klipper-lb) | デプロイしない | ロードバランシングを管理したくない、Cloudflare を購入 | --disable servicelb |
| DNS | CoreDNS | - | デフォルトのままで問題なし | - |
| Storage Class | Local-path-provisioner | Longhorn | 分散ストレージ、高可用性、バックアップ機能 | --disable local-storage |
| CNI | Flannel | Cilium | eBPF パフォーマンス、ネットワークポリシー、可観測性 | --flannel-backend=none --disable-network-policy |

環境準備
必須ツール
まず、k3sup、kubectl、Helm などのツールが正しくインストールされていることを確認してください(各 GitHub プロジェクトが提供するインストール説明を参照):
k3sup version
kubectl version
helm version
以下のように表示されます:

サーバー要件
最小限の 3 ノード高可用コントロールプレーン(Ubuntu 24.04 を使用した例)として機能する、少なくとも 3 台のクラウドサーバーを準備してください(推奨構成 ≥ 4C4G)。各ノードの IP を事前に記録し、SSH 公開鍵が配布されていることを確認し、ローカル秘密鍵のパスを把握してください。これらは後続のステップで使用されます。
初期コントロールプレーンのデプロイ
k3sup を使用して初期コントロールノードをデプロイします:
k3sup install \
--ip 初期ノード IP \
--user root \
--ssh-key 秘密鍵位置 \
--k3s-channel latest \
--cluster \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"
以下のように表示されます:

インストール完了後、k3sup は自動的に kubeconfig を現在のディレクトリにコピーします。この設定を直接使用することもできますが、より堅牢な方法は既存の設定ファイルとマージすることです。
kubeconfig のマージ
- 現在の kubeconfig をバックアップします(デフォルトは
~/.kube/config):
cp ~/.kube/config ~/.kube/config.backup
fish shell(参考用):
cp $KUBECONFIG {$KUBECONFIG}.backup
- 新旧の kubeconfig を 1 つのフラットファイルにマージします:
KUBECONFIG=~/.kube/config:./kubeconfig kubectl config view --flatten > ~/.kube/config.new
fish shell(参考用):
KUBECONFIG=$KUBECONFIG:./kubeconfig kubectl config view --flatten > kubeconfig-merged.yaml
- 新しいファイルの内容が正しいことを確認した後、古い設定を上書きします:
mv ~/.kube/config.new ~/.kube/config
fish shell:
mv ./kubeconfig-merged.yaml $KUBECONFIG
- 新しいコンテキストが有効になったことを確認します:
kubectl config get-contexts
kubectl config use-context default
Cilium のインストール(Flannel の置き��え)
k3s をインストールする際、デフォルト CNI(Flannel)を無効化したため、ノード間の通信が一時的に不可能です。計画に従い、Cilium をデプロイしてネットワークとネットワークポリシー機能を提供します。
Helm を使用して Cilium をインストールします:
# Cilium Helm リポジトリを追加
helm repo add cilium https://helm.cilium.io/
# Helm リポジトリを更新
helm repo update
# Cilium CNI をインストール(シングルレプリカ、デフォルトモード)
helm install cilium cilium/cilium \
--namespace kube-system \
--set operator.replicas=1 \
--set ipam.mode=kubernetes
クラスタが既に kube-proxy を無効化している場合、追加で
--set kubeProxyReplacement=strictを指定できます。本チュートリアルではより多くのシナリオとの互換性を保つため、デフォルト値を使用しています。
実行完了後、以下が表示されます:

Cilium コンポーネントの起動完了を待ちます:
# Cilium 関連 Pod の状態を確認
kubectl get pods -n kube-system -l k8s-app=cilium
# ノード状態を確認(NotReady から Ready に変わるはず)
kubectl get nodes

ノードが Cilium に切り替わった後、NotReady から Ready に変わるはずです。次に k3sup を使用して他の 2 つのコントロールノードを追加します。
コントロールプレーンの拡張
高可用性を実現するには、少なくとも 3 つのコントロールノードが必要です。以下のコマンドを使用して 2 番目のコントロールノードを追加します:
k3sup join \
--ip 2 番目のノード IP \
--user root \
--ssh-key 秘密鍵位置 \
--server-ip 初期ノード IP \
--server \
--k3s-channel latest \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"
同じ方法で 3 番目のコントロールノードを追加します:
k3sup join \
--ip 3 番目のノード IP \
--user root \
--ssh-key 秘密鍵位置 \
--server-ip 初期ノード IP \
--server \
--k3s-channel latest \
--k3s-extra-args "--disable traefik --disable servicelb --disable local-storage --flannel-backend=none --disable-network-policy"
数分待った後、クラスタの状態を確認します:
kubectl get nodes
3 つのコントロールノードがすべて Ready 状態になったら、コントロールプレーンの構築は完了です。

Nginx Ingress Controller のインストール
k3s デフォルトの Traefik を置き換え、Nginx Ingress Controller をインストールします:
# Nginx Ingress Helm リポジトリを追加
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# Nginx Ingress Controller をインストール(長時間待つ必要がある場合があります)
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.hostPort.enabled=true \
--set controller.hostPort.ports.http=80 \
--set controller.hostPort.ports.https=443 \
--set controller.service.type=ClusterIP
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Longhorn 分散ストレージのインストール
Longhorn は Rancher によって開発されたクラウドネイティブ分散ブロックストレージシステムで、高可用性、バックアップ、スナップショットなどのエンタープライズグレード機能を提供します。k3s デフォルトの local-path-provisioner と比較して、Longhorn はノード間の永続ストレージをサポートしています。
前提条件の確認
Longhorn をインストールする前に、各ノードに必要な依存関係がインストールされていることを確認する必要があります。Ansible を使用してバッチ処理したい場合は、後続の例を参照してください:
# 各ノードで実行(SSH 経由)
# open-iscsi の確認とインストール
apt update
apt install -y open-iscsi nfs-common
# 起動と自動起動の設定
systemctl enable --now iscsid
systemctl status iscsid
Ansible を使用して依存関係をバッチインストールしたい場合は、以下のタスク片を参照できます:
---
- name: Setup K3s nodes with Longhorn dependencies and CrowdSec
hosts: k3s
become: true
vars:
crowdsec_version: "latest"
tasks:
# ============================================
# Longhorn Prerequisites
# ============================================
- name: Install Longhorn required packages
ansible.builtin.apt:
name:
- open-iscsi # iSCSI support for volume mounting
- nfs-common # NFS support for backup target
- util-linux # Provides nsenter and other utilities
- curl # For downloading and API calls
- jq # JSON processing for Longhorn CLI
state: present
update_cache: true
tags: longhorn
- name: Enable and start iscsid service
ansible.builtin.systemd:
name: iscsid
enabled: true
state: started
tags: longhorn
- name: Load iscsi_tcp kernel module
community.general.modprobe:
name: iscsi_tcp
state: present
tags: longhorn
- name: Ensure iscsi_tcp loads on boot
ansible.builtin.lineinfile:
path: /etc/modules-load.d/iscsi.conf
line: iscsi_tcp
create: true
mode: '0644'
tags: longhorn
- name: Check if multipathd is installed
ansible.builtin.command: which multipathd
register: multipathd_check
failed_when: false
changed_when: false
tags: longhorn
- name: Disable multipathd if installed (conflicts with Longhorn)
ansible.builtin.systemd:
name: multipathd
enabled: false
state: stopped
when: multipathd_check.rc == 0
tags: longhorn
Longhorn のデプロイ
Helm を使用して Longhorn をインストールします:
# Longhorn Helm リポジトリを追加
helm repo add longhorn https://charts.longhorn.io
helm repo update
# Longhorn をインストール(長時間待つ必要がある場合があります)。ディスク容量を節約するため、ここではシングルレプリカのみを設定しています。必要に応じて調整してください
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--set defaultSettings.defaultDataPath="/var/lib/longhorn" \
--set persistence.defaultClass=true \
--set persistence.defaultClassReplicaCount=1
Longhorn コンポーネントの起動を待ちます:
# Longhorn コンポーネントの状態を確認
kubectl get pods -n longhorn-system
# StorageClass を確認
kubectl get storageclass

Longhorn UI へのアクセス(オプション)
Longhorn はストレージボリュームを管理するための Web UI を提供しています。ポート転送を使用して一時的にアクセスできます:
# ローカルにポート転送
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8081:80
# ブラウザで http://localhost:8081 にアクセス
確認完了後、ターミナルで
Ctrl+Cを押してポート転送を停止し、ローカルポートの継続的な占有を避けてください。
Agent ノードの追加
ここまでで、3 ノードの高可用コントロールプレーン(control-plane)を構築しました。本番環境では、control-plane ノード上で実際のアプリケーションプログラムを実行したくありません(API Server、etcd などのコアコンポーネントのリソースを占有するため)。
したがって、ワークロード(Pods)を実行するための専用 Agent ノード(Worker ノードとも呼ばれます)を追加する必要があります。
インストール前の依存関係
control-plane ノードと同様に、Agent ノードも Longhorn の依存関係を満たす必要があります(これらのノードが永続ボリュームをスケジュールおよび保存できるようにする場合)。
追加予定のすべての Agent ノードで、事前に以下のコマンドを実行してください:
# 各 Agent ノードで実行(SSH 経由)
apt update
apt install -y open-iscsi nfs-common
# 起動と自動起動の設定
systemctl enable --now iscsid
追加コマンドの実行
Agent ノードを追加するコマンドは control-plane ノードを追加するコマンドとほぼ同じですが、2 つの重要な違いがあります:--server フラグを使用せず、追加パラメータが不要です。
k3sup join \
--ip <AGENT_ノード IP> \
--user root \
--ssh-key <秘密鍵位置> \
--server-ip <任意の Control ノード IP> \
--k3s-channel latest
ノード状態の確認
複数の Agent ノードを一度に追加できます。追加完了後、数分待つと Cilium と Longhorn のコンポーネントが新しいノードに自動的にスケジュールされます。
kubectl を使用してクラスタの状態を確認します:
kubectl get nodes -o wide
新しく追加されたノードが表示され、ROLE 列は <none> と表示されるはずです(k3s では、<none> は agent/worker ロールを表します)。
同時に、Cilium と Longhorn の Pod が新しいノード上で正常に起動したかどうかを監視できます:
# Cilium agent は新しいノード上で起動するはず
kubectl get pods -n kube-system -o wide
# Longhorn instance-manager も新しいノード上で起動するはず
kubectl get pods -n longhorn-system -o wide
これで、クラスタは高可用コントロールプレーンとアプリケーション実行用のワーカーノードを備えました。
次のステップ
- Argo CD、Flux などの GitOps ツールを設定し、クラスタの宣言型管理プロセスを標準化します。
- Prometheus、Loki、Grafana などの可観測性コンポーネントをデプロイし、監視とログシステムを改善します。
- Ansible Playbook を使用してノード初期化とコンポーネントアップグレードを自動化し、後続の運用コストを削減します。